// This is mostly a simplified version of the BSD FTP code....
// Most of this is indepenant of the actual DUftp user interface code.
// stuff that isn't is wrapped in '#ifdef Ftp_progress'.
// If Ftp_progress is defined, then these routines expect a dialog
// called Ftp_progress to exist, containing (at least) two text objects
// one called Ftp_operation and one called Ftp_status. If the dialog
// doesn't exist, the FTP routines will use alert's for their progress
// messages instead.
#include <DULIB.H>
#include <TYPES.H>
#include <SYS\SOCKET.H>
#include <ARPA\FTP.H>
#include <ARPA\TELNET.H>
#include <VARARGS.H>
#include <NETDB.H>
#include <SETJMP.H>
#include <TIME.H>
#include <STAT.H>
#include <SIGNAL.H>
#include <ERRNO.H>
#include <PORTLIB.H>
#include <TIME.H>
#include <CTYPE.H>
#include "ftp.h"
// Omit this next include to use the routines in other programs
#include "duftp_n.h"
#include "globals.h"
DU_servent *sp; // service spec for tcp/ftp
char homedir[FMSIZE];
FILE *cin, *cout;
int connected; // are we connected to a server ?
char *hostname; // name of the host we are connected to
int type;
int form;
int mode;
int stru;
int bytesize;
int cpend;
int proxy;
int crflag;
char pasv[64]; // passive port for proxy data connection
struct sockaddr_in hisctladdr;
struct sockaddr_in data_addr;
int data;
int abrtflag;
int ptflag;
int allbinary;
struct sockaddr_in myctladdr;
off_t restart_point;
int code;
int macnum;
char reply_string[BUFSIZ]; // last line of previous reply
// Signal handler for lost connections
void lostpeer(int a)
{
if (connected) {
if (cout != NULL) {
(void) shutdown(fileno(cout), 1+1);
(void) fclose(cout);
cout = NULL;
}
if (data >= 0) {
(void) shutdown(data, 1+1);
(void) close(data);
data = -1;
}
connected = 0;
}
/* pswitch(1);
if (connected) {
if (cout != NULL) {
(void) shutdown(fileno(cout), 1+1);
(void) fclose(cout);
cout = NULL;
}
connected = 0;
}
proxflag = 0;
pswitch(0);*/
}
// Initialises all the stuff to do with the FTP routines
void initialise_ftp(void)
{
char *cp,*home;
struct passwd *pw = NULL;
// MiNT-NET INITIALISATION
chdir("u:/"); // Must change to root partition here, else getservbyname will fail
sp=(DU_servent*)getservbyname("ftp","tcp");
if (sp==0)
{
form_alert(1,"[3][ ERROR: ftp/tcp: unknown service. | This probably means you haven't | installed MiNT-net correctly, as | '/etc/services' cannot be opened. ][ EXIT ]");
close_down();
exit(1);
}
// Set up the home directory
cp = getlogin();
if (cp != NULL) {
pw = getpwnam(cp);
}
if (pw == NULL)
pw = getpwuid(getuid());
if (pw != NULL) {
sprintf(homedir, "%s", pw->pw_dir);
}else{
getcwd(homedir,0);
}
home = homedir;
// Set up defaults for FTP.
type=TYPE_I; // transferr type == binary (I know, it violates the RFC and is
// very lazy to just use binary.....
// **NOTE - ok, I've actually used the correct types further on.
form = FORM_N; // form - non-print
mode = MODE_S; // streaming mode
stru = STRU_F; // structure=file (no record or page formatting)
bytesize = 8; // 1 byte == 8 bits
cpend = 0; // no pending replies
proxy = 0; // proxy not active
crflag = 1; // strip c.r. on ascii gets
data = -1;
abrtflag = 0;
ptflag = 0;
restart_point = 0;
// Initially, we aren't connected
connected=0;
// If we lost the ftp connection, better close down the link
signal(SIGPIPE, lostpeer);
}
// Connect to peer server and auto-login, if possible.
void connect_to_server(char *server_name)
{
char al[200];
char *host;
short port;
if (connected) {
sprintf(al,"[3][ Already connected to | '%s' | - you must close this first. ][ Ok ]",hostname);
form_alert(1,al);
return;
}
port = sp->s_port;
host = hookup(server_name, port);
if (host)
{
connected = 1;
// Don't bother with system type enquiry on the local machine
if (strcmp(inet_ntoa(hisctladdr.sin_addr),"127.0.0.1"))
{
allbinary = 0;
type=TYPE_A; // transferr type == ascii for sending commands
if (send_command("SYST")==COMPLETE) // Check remote system type. Some FTP servers don't understand
{ // the SYST message, so we may not always be able to tell.....
register char *cp, c;
cp = (char*)index(reply_string+4, ' ');
if (cp == NULL)
cp = (char*)index(reply_string+4, '\r');
if (cp)
{
if (cp[-1] == '.')
cp--;
c = *cp;
*cp = '\0';
}
#ifdef Ftp_progress
sprintf(al,"Remote system type is '%s'.",reply_string+4);
set_dialog_text(Ftp_progress, Ftp_status, al);
dialog_display(Ftp_progress);
#else
sprintf(al,"[1][ Remote system type is | '%s'.][ ok ]",reply_string+4);
form_alert(1,al);
#endif
if (cp) *cp = c;
}
allbinary = 1; // This violates the RFC - but I'm not worrying about that right now
type=TYPE_I; // so all-binary is what we get - at least you can get GIF's with it ;)
}
}
}
// don't allow commands to abort at the moment
/*sig_t cmdabort(int a)
{
extern jmp_buf ptabort;
printf("\n");
(void) fflush(stdout);
abrtflag++;
if (ptflag)
longjmp(ptabort,1);
}*/
short send_command(char *command_to_send)
{
int r;
// sig_t (*oldintr)();
abrtflag = 0;
if (cout==NULL) {
form_alert(1,"[3][ ERROR: | No control connection for command? ][ What? ]");
return 0;
}
// oldintr = signal(SIGINT,cmdabort);
fprintf(cout, "%s\r\n", command_to_send);
(void) fflush(cout);
cpend = 1;
r = getreply(!strcmp(command_to_send, "QUIT"));
// if ((abrtflag!=0)&&((__Sigfunc)oldintr!=SIG_IGN)) (*oldintr)();
// (void) signal(SIGINT, oldintr);
return r;
}
int getreply(int expecteof)
{
register int c, n;
register int dig;
register char *cp;
int originalcode = 0, continuation = 0;
// sig_t (*oldintr)();
int pflag = 0;
char *pt = pasv;
// oldintr = signal(SIGINT,cmdabort);
for (;;) {
dig = n = 0; code = 0;
cp = reply_string;
while ((c = getc(cin)) != '\n') {
/*
* For some reason the MintLib PL44's sprintf generates garbage
* with several %c's in a row, so we use fputc here. Thanks to
* Kay Roemer for reporting this! :-)
*/
if (c==IAC) { /* handle telnet commands */
switch (c=getc(cin))
{
case WILL:
case WONT:
c = getc(cin);
fputc(IAC, cout);
fputc(DONT, cout);
fputc(c, cout);
(void) fflush(cout);
break;
case DO:
case DONT:
c = getc(cin);
fputc(IAC, cout);
fputc(WONT, cout);
fputc(c, cout);
(void) fflush(cout);
break;
default:
break;
}
continue;
}
dig++;
// End of transmission - peer has close connection
if (c == EOF) {
if (expecteof) {
// (void) signal(SIGINT,oldintr);
code = 221;
return 0;
}
lostpeer((int)SIG_IGN);
form_alert(1,"[3][ Service not available, | remote server has closed | connection. ][ Bugger ]");
return 4;
}
// if ((c != '\r')||((n=='5')&&(dig>4))) {
// (void) putchar(c);
// }
if ((dig<4)&&(isdigit(c)))
code = code * 10 + (c - '0');
if ((!pflag)&&(code==227))
pflag = 1;
if (((dig>4)&&(pflag==1))&&(isdigit(c)))
pflag = 2;
if (pflag==2)
{
if (c != '\r' && c != ')')
*pt++ = c;
else {
*pt = '\0';
pflag = 3;
}
}
if ((dig==4)&&(c=='-'))
{
if (continuation)
code = 0;
continuation++;
}
if (n==0) n = c;
if (cp<&reply_string[sizeof(reply_string)-1])
*cp++ = c;
}
if ((continuation)&&(code!=originalcode))
{
if (originalcode==0)
originalcode = code;
continue;
}
*cp = '\0';
if (n != '1')
cpend = 0;
// (void) signal(SIGINT,oldintr);
if ((code==421)||(originalcode==421))
lostpeer((int)SIG_IGN);
// if (((abrtflag!=0)||(cmdabort!=0))&&((__Sigfunc)oldintr!=SIG_IGN))
// (*oldintr)();
return (n-'0');
}
}
char *hookup(char *host, int port)
{
register DU_hostent *hp = 0;
int s,len;
char al[200];
static char hostnamebuf[80];
short con;
// First, lets get the IP address from the nameserver